package com.quectel.sys.module.sys.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.quectel.constant.global.SqlConstants;
import com.quectel.constant.global.SystemConstants;
import com.quectel.sys.constants.RedisCacheConstants;
import com.quectel.sys.module.sys.dao.SysRoleDao;
import com.quectel.sys.module.sys.dao.SysUserDao;
import com.quectel.sys.module.sys.dao.SysUserRoleDao;
import com.quectel.sys.module.sys.dto.SysGroupDto;
import com.quectel.sys.module.sys.dto.SysRoleDto;
import com.quectel.sys.module.sys.dto.SysTenantDto;
import com.quectel.sys.module.sys.dto.SysUserDto;
import com.quectel.sys.module.sys.entity.SysRoleEntity;
import com.quectel.sys.module.sys.entity.SysUserEntity;
import com.quectel.sys.module.sys.entity.SysUserRoleEntity;
import com.quectel.sys.module.sys.service.SysGroupService;
import com.quectel.sys.module.sys.service.SysTenantService;
import com.quectel.sys.module.sys.service.SysUserService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.kit.CacheKit;
import com.quectel.util.kit.Snowflake;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

/**
 * @author caolu
 * @email louis.cao@quectel.com
 * @date 2019-04-01 13:06:24
 */
@DubboService
public class SysUserServiceImpl implements SysUserService {

    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysRoleDao sysRoleDao;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;
    @Autowired
    private SysGroupService sysGroupService;
    @Autowired
    private SysTenantService sysTenantService;

    private static final String TENANT_ADMIN = "SMART_CITY_SYS_TENANT_ADMIN:";


    @Override
    public List<SysUserDto> selectCacheListByBatchIds(List<Long> ids) {
        List<SysUserDto> list = new ArrayList<>();
        for (Long id : ids) {
            SysUserDto sysUserDto = selectCacheById(id);
            if (sysUserDto != null) {
                list.add(sysUserDto);
            }
        }
        return list;
    }

    @Override
    public SysUserDto getAdminByTenantId(Long tenantId, Boolean byCache) {

        Supplier<SysUserDto> supplier = () -> {
            SysUserEntity sysUserEntity = sysUserDao.selectOne(new LambdaQueryWrapper<SysUserEntity>().eq(SysUserEntity::getTenantId, tenantId)
                    .eq(SysUserEntity::getIsTenantAdmin, SystemConstants.YES));

            SysUserDto sysUserDto = CopyUtils.copyObj(sysUserEntity, SysUserDto.class);

            if (sysUserDto != null) {
                List<SysRoleEntity> sysRoleEntities = sysUserRoleDao.selectRolesByUserId(sysUserDto.getId());
                sysUserDto.setUserRoleList(CopyUtils.copyList(sysRoleEntities, SysRoleDto.class));
            }
            return sysUserDto;
        };

        if (byCache == null || byCache) {
            SysUserDto dto = CacheKit.cacheToRedis(supplier, TENANT_ADMIN + tenantId, 15 * 60);
            return dto;
        }

        return supplier.get();
    }

    @Override
    public List<SysUserDto> queryList(Map<String, Object> params) {
        List<SysUserEntity> list = sysUserDao.queryList(params);
        return CopyUtils.copyList(list, SysUserDto.class);
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return sysUserDao.queryTotal(params);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(SysUserDto dto) {


        dto.setId(Snowflake.nextId());
        dto.setStatus((byte) 1);
        Date now = new Date();

        saveUserRoleRelation(dto);


        SysUserEntity entity = CopyUtils.copyObj(dto, SysUserEntity.class);
        sysUserDao.insert(entity);
    }

    @Override
    public void updateByIdWithoutRelation(SysUserDto dto) {
        SysUserEntity entity = CopyUtils.copyObj(dto, SysUserEntity.class);
        sysUserDao.updateById(entity);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateById(SysUserDto dto) {
        SysUserEntity entity = CopyUtils.copyObj(dto, SysUserEntity.class);
        sysUserDao.updateById(entity);

        if (SystemConstants.YES.equals(dto.getIsTenantAdmin())) {
            // 租户管理员不允许修改角色关系
            return;
        }
        saveUserRoleRelation(dto);
    }


    @Override
    public SysUserDto selectCacheById(Long id) {
        return CacheKit.cacheToRedis(
                () -> selectById(id),
                RedisCacheConstants.SYS_USER_BY_ID + id,

                SystemConstants.NOT_NULL_CACHE_EXPIRE_SECONDS

        );
    }

    @Override
    public SysUserDto selectById(Long id) {
        SysUserEntity entity = sysUserDao.selectById(id);
        SysUserDto sysUserDto = CopyUtils.copyObj(entity, SysUserDto.class);
        if (sysUserDto != null) {
            List<SysRoleEntity> sysRoleEntities = sysUserRoleDao.selectRolesByUserId(id);
            sysUserDto.setUserRoleList(CopyUtils.copyList(sysRoleEntities, SysRoleDto.class));

            SysGroupDto sysGroupDto = sysGroupService.selectById(sysUserDto.getGroupId());
            sysUserDto.setSysGroup(sysGroupDto);
            SysTenantDto sysTenantDto = sysTenantService.selectById(sysUserDto.getTenantId());
            sysUserDto.setSysTenant(sysTenantDto);
        }
        return sysUserDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(Long id) {
        sysUserDao.deleteById(id);
        //清除用户与角色的关系
        sysUserRoleDao.delete(new QueryWrapper<SysUserRoleEntity>().eq("user_id", id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatch(Long[] ids) {
        for (Long id : ids) {
            deleteById(id);
        }
    }

    @Override
    public SysUserDto selectByAccount(String account) {
        SysUserEntity entity = sysUserDao.selectOne(new QueryWrapper<SysUserEntity>().eq("account", account).last(SqlConstants.MYSQL_LIMIT_ONE));
        return CopyUtils.copyObj(entity, SysUserDto.class);
    }

    @Override
    public void updatePassword(Long userId, String password) {
        SysUserEntity sysUserEntity = new SysUserEntity();
        sysUserEntity.setId(userId);
        sysUserEntity.setPassword(password);
        sysUserDao.updateById(sysUserEntity);
    }

    private void saveUserRoleRelation(SysUserDto dto) {
        sysUserRoleDao.delete(new QueryWrapper<SysUserRoleEntity>().eq("user_id", dto.getId()));
        if (CollectionUtils.isEmpty(dto.getUserRoleList())) {
            return;
        }
        for (SysRoleDto sysRoleDto : dto.getUserRoleList()) {
            SysUserRoleEntity sysUserRoleEntity = new SysUserRoleEntity();
            sysUserRoleEntity.setId(Snowflake.nextId());
            sysUserRoleEntity.setUserId(dto.getId());
            sysUserRoleEntity.setRoleId(sysRoleDto.getId());
            sysUserRoleDao.insert(sysUserRoleEntity);
        }
    }

    @Override
    public List<SysUserDto> selectListByGroupId(Serializable groupId) {
        List<SysUserEntity> sysUserEntitys = sysUserDao.selectList(new QueryWrapper<SysUserEntity>().eq("group_id", groupId));
        return CopyUtils.copyList(sysUserEntitys, SysUserDto.class);
    }
}
